home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / MacTech® Magazine / Volume 04 - 1988 / 04.11 Nov 88 / IAC / Editor Stuff / Editor.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-09-19  |  23.9 KB  |  987 lines  |  [TEXT/MPS ]

  1. /***
  2.  *
  3.  * File:        Editor.c
  4.  *
  5.  * Package:        Mainline
  6.  *
  7.  * Description:    This is the mainline for the editor program to test the
  8.  *                Inter Application Communications (IAC) driver. Some code
  9.  *                from the Apple "sample.c" was adapted.
  10.  *
  11.  * Structure:    In this source the following structure is used:
  12.  *                    includes & defines
  13.  *                    global variable definitions
  14.  *                    main()
  15.  *                    initialization routines
  16.  *                    the menu dispatcher menu_tree()
  17.  *                    dialog-box handlers
  18.  *
  19.  * Author:
  20.  *    FEA        6/88 - 7/88
  21.  */
  22.  
  23. # include    <types.h>
  24. # include    <memory.h>
  25. # include    <quickdraw.h>
  26. # include    <toolutils.h>
  27. # include    <windows.h>
  28. # include    <controls.h>
  29. # include    <fonts.h>
  30. # include    <events.h>
  31. # include    <dialogs.h>
  32. # include    <menus.h>
  33. # include    <desk.h>
  34. # include    <textedit.h>
  35. # include    <segload.h>
  36. # include    <string.h>
  37. # include    <resources.h>
  38.  
  39. # include    <iac.h>
  40. # undef PUBLIC
  41. # include    <Editor.h>
  42.  
  43. #define noErr          0          /* 0 for success */
  44.  
  45. extern _DataInit();
  46.  
  47.  
  48. /**
  49.  * Routine: main()
  50.  *
  51.  *        Mainline of the test program
  52.  */
  53.  
  54. int main()
  55. {
  56. short            init_result;        /* NULL if OK */
  57. short            item;                /* alert button */
  58. Rect            screenRect;
  59. Rect            dragRect;
  60. Rect            txRect;
  61. Point            mousePt;
  62. EventRecord     myEvent;
  63. WindowPtr        theActiveWindow;
  64. WindowPtr        whichWindow;
  65.  
  66. win_dataH        the_data_H;            /* data associated with a window */
  67.  
  68.  
  69. extern    void         menu_tree(), do_key(), poll_iac();
  70. extern    void        ext_move();
  71. extern    short        edit_init();
  72. extern    WindowPtr    myWindow;
  73.  
  74.     UnloadSeg(_DataInit);
  75.     init_result = edit_init();
  76.     if (init_result)
  77.     {
  78.         item = StopAlert(NO_IAC, nil);
  79.         return 0;            /* allow C runtime cleanup */
  80.     }
  81.  
  82.     UnloadSeg(edit_init);        /* if we get here, IAC open */
  83.  
  84.     /* basic window setup is handled by 'new' and 'open' commands */
  85.     screenRect = qd.screenBits.bounds;
  86.     SetRect(&dragRect, 4, 20 + 4, screenRect.right-4, screenRect.bottom-4);
  87.  
  88.     /* The One True Event Loop */
  89.     DoneFlag = false;
  90.     for ( ;; )
  91.     {
  92.         if (DoneFlag)
  93.         {
  94.             break;        /* from main event loop */
  95.         }
  96.         
  97.         /*
  98.          * Main Event tasks:
  99.          */
  100.          
  101.         theActiveWindow = FrontWindow();        /* Used often, avoid repeated calls */
  102.  
  103.         if (myWindow && (myWindow == theActiveWindow))
  104.         {
  105.             GetMouse(&mousePt);
  106.             SetCursor(PtInRect(&mousePt, &myWindow->portRect) ? *ibeamHdl : &qd.arrow);
  107.             TEIdle(TextH);
  108.  
  109.             the_data_H = (win_dataH) GetWRefCon (myWindow);
  110.             if ((**the_data_H).dirty)
  111.             {
  112.                 EnableItem (MyMenus[fileMenu], saveCommand);
  113.             }
  114.             else
  115.             {
  116.                 DisableItem (MyMenus[fileMenu], saveCommand);
  117.             }
  118.         }
  119.         
  120.         if (!WaitNextEvent(everyEvent, &myEvent, SLEEP, nil))
  121.         {
  122.             /*    A null or system event! Here is the place for IAC polling.
  123.                 We only poll if we have link targets to check. */
  124.             if (theActiveWindow && extent_count)
  125.             {
  126.                 poll_iac(theActiveWindow);
  127.             }
  128.             continue;
  129.         }
  130.  
  131.         the_data_H = (win_dataH) GetWRefCon(theActiveWindow);
  132.         TextH = (**the_data_H).wind_TEH;
  133.         
  134.         switch (myEvent.what)
  135.         {
  136.             case mouseDown:
  137.                 switch (FindWindow(&myEvent.where, &whichWindow))
  138.                 {
  139.                     case inSysWindow:
  140.                         SystemClick(&myEvent, whichWindow);
  141.                         break;
  142.  
  143.                     case inMenuBar:
  144.                         menu_tree(MenuSelect(&myEvent.where));
  145.                         break;
  146.  
  147.                     case inDrag:
  148.                         DragWindow(whichWindow, &myEvent.where, &dragRect);
  149.                         break;
  150.  
  151.                     case inGrow:    /* There is no grow box. */
  152.                         break;
  153.  
  154.                     case inContent:
  155.                         if (whichWindow != theActiveWindow)
  156.                         {
  157.                             SelectWindow(whichWindow);
  158.                         }
  159.                         else if (whichWindow == myWindow)
  160.                             {
  161.                                 ext_move(&myEvent, theActiveWindow);
  162.                             }
  163.                         break;
  164.  
  165.                     default:
  166.                         break;
  167.                 }/*endsw FindWindow*/
  168.                 break;
  169.  
  170.             case autoKey:    /* ignore command-key */
  171.                 if (myWindow == theActiveWindow)
  172.                 {
  173.                     do_key(myEvent.message);    /* this lets us check extents */
  174.                 }
  175.                 break;
  176.  
  177.             case keyDown:
  178.                 if (myWindow == theActiveWindow)
  179.                 {
  180.                     if (myEvent.modifiers & cmdKey)
  181.                     {
  182.                         menu_tree(MenuKey(myEvent.message & charCodeMask));
  183.                     }
  184.                     else
  185.                     {
  186.                         do_key(myEvent.message);    /* this lets us check extents */
  187.                     }
  188.                 }
  189.                 break;
  190.  
  191.             case app4Evt:    /* suspend/resume */
  192.                 break;
  193.  
  194.             case activateEvt:
  195.                 if ((WindowPtr) myEvent.message == myWindow)
  196.                 {
  197.                     if (myEvent.modifiers & activeFlag)
  198.                     {
  199.                         TEActivate(TextH);
  200.                         DisableItem(MyMenus[editMenu], undoCommand);
  201.                     }
  202.                     else
  203.                     {
  204.                         TEDeactivate(TextH);
  205.                         EnableItem(MyMenus[editMenu], undoCommand);
  206.                     }
  207.                 }
  208.                 break;
  209.  
  210.             case updateEvt:
  211.                 if ((WindowPtr) myEvent.message == theActiveWindow)
  212.                 {
  213.                     BeginUpdate(theActiveWindow);
  214.                     EraseRect(&theActiveWindow->portRect);
  215.                     TEUpdate(&theActiveWindow->portRect, TextH);
  216.                     EndUpdate(theActiveWindow);
  217.                 }
  218.                 break;
  219.  
  220.             default:
  221.                 break;
  222.  
  223.         } /* endsw myEvent.what */
  224.  
  225.     } /* for */
  226.  
  227.     if (myWindow)
  228.     {
  229.         /* shut down code, including "save changes?" */
  230.         CloseWindow(myWindow);
  231.     }
  232.     return 0;        /* Return from main() to allow C runtime cleanup */
  233. }
  234.  
  235.  
  236.  /**
  237.  * Routine: chk_extent
  238.  *
  239.  *        This routine checks the selection range in the TE record to determine
  240.  *    if it intersects the current extent. If not, it checks the entire set of
  241.  *    extents to try and identify the extent it might intersect. If we are not
  242.  *    currently in an exent, the 'current extent' structure is filled with -1s
  243.  *    as is 'curr_ext_no'.
  244.  */
  245.  
  246. # define __SEG__ Main
  247. Boolean    chk_extent(TextH, the_extH, ext_cnt)
  248.     TEHandle        TextH;        /* The TextEdit record to check */
  249.     extentH            the_extH;    /* handle to extent block */
  250.     short            ext_cnt;    /* how many extents to process */
  251. {
  252. short            strt, endd;            /* range in TE record */
  253. short            i;                    /* scratch */
  254. exTable            ext_recs;
  255. Boolean            left, right;
  256.  
  257.  
  258.     if (ext_cnt)
  259.     {        
  260.         strt = (**TextH).selStart;
  261.         endd = (**TextH).selEnd;
  262.         ext_recs = *the_extH;
  263.  
  264.         /* Check last extent used. If not in that, scan entire table.
  265.          * We are affecting an extent if EITHER the start or end of the TE
  266.          * selection falls between the start and end of the extent (inclusive).
  267.          */
  268.         left =    (curr_ext.ext_strt <= strt) && (curr_ext.ext_end >= strt);
  269.         right =    (curr_ext.ext_strt <= endd) && (curr_ext.ext_end >= endd);
  270.         if (left ||    right)    /* overlap on either end */
  271.         {
  272.             return (true);    /* existing info alright as is */
  273.         }
  274.         else        /* switched, check all */
  275.         {
  276.             for (i=0; i<ext_cnt; i++)
  277.             {
  278.                 left =    (ext_recs[i].ext_strt <= strt) && (ext_recs[i].ext_end >= strt);
  279.                 right = (ext_recs[i].ext_strt <= endd) && (ext_recs[i].ext_end >= endd);
  280.                 if (left ||    right)    /* this is now the current extent */
  281.                 {
  282.                     curr_ext.ext_strt =  ext_recs[i].ext_strt;
  283.                     curr_ext.ext_end  =  ext_recs[i].ext_end;
  284.                     curr_ext.hat_check = ext_recs[i].hat_check;
  285.                     curr_ext.ed_level =  ext_recs[i].ed_level;
  286.                     curr_ext_no = i;
  287.                     return (true);
  288.                 }
  289.             } /* end for */
  290.         } /* end else */
  291.     } /* end there-are-extents */
  292.  
  293.     curr_ext.ext_strt =  -1;    /* not current in an extent */
  294.     curr_ext.ext_end  =  -1;
  295.     curr_ext.hat_check = -1;
  296.     curr_ext.ed_level =  -1;
  297.     curr_ext_no = -1;
  298.     return(false);
  299. }
  300.  
  301.  
  302. /**
  303.  * Routine: ext_write
  304.  *
  305.  *        This routine handles the mechanics of actually writing an extent's
  306.  *    data to the IAC driver.
  307.  */
  308.  
  309. # define __SEG__ Main
  310. short    ext_write(TextH, strt, sz, the_doc, the_hatcheck, the_ed)
  311.     TEHandle    TextH;            /* The TextEdit handle */
  312.     short        strt;            /* position of 1st char to write */
  313.     short        sz;                /* count of bytes */
  314.     long        the_doc;        /* which doc */
  315.     short        the_hatcheck;
  316.     short       *the_ed;
  317. {
  318. short            iac_code;            /* result from IAC call */
  319. long            data_size;
  320. Handle            ext_data, t_base;
  321. long            *l_ptr;                /* recast to ease setting up hdr */
  322.  
  323. # define        HDR_SIZE 8
  324.  
  325.     ext_data = NewHandle (sz + HDR_SIZE);
  326.     l_ptr = (long *)(*ext_data);
  327.     *l_ptr = TXT_FMT;
  328.     *(l_ptr+1) = (long) sz;
  329.     t_base = (**TextH).hText;
  330.     BlockMove (*t_base + strt,                /* source */
  331.                (*ext_data) + HDR_SIZE,        /* dest */
  332.                (long) sz);
  333.     iac_code = iac_write_data(the_doc, the_hatcheck, the_ed, 1,    ext_data);
  334.     DisposHandle(ext_data);
  335.     return (iac_code);
  336. }
  337.  
  338.  
  339. /**
  340.  * Routine: ext_read
  341.  *
  342.  *        This routine handles the mechanics of actually reading an extent's
  343.  *    data from the IAC driver. If successful the edition_level for the extent
  344.  *    is updated.
  345.  */
  346.  
  347. # define __SEG__ Main
  348. short    ext_read(w_Ptr, the_ed, which)
  349.     WindowPtr    w_Ptr;
  350.     short       *the_ed;        /* edition of the extent to read */
  351.     short        which;        /* which extent (zero-based) */
  352. {
  353. win_dataH        the_data_H;            /* data associated with a window */
  354. extentH            the_extH;            /* handle to extent block */
  355. TEHandle        TextH;                /* The TextEdit handle */
  356. exTable            ext_recs;            /* for walking extents for adjusting */
  357. long            fmt_code;            /* actual data format from IAC */
  358. long            fmt_pref[3];        /* format prefs, descending desirability */
  359. long            old_st, old_end;    /* TE selection before poll */
  360. short            delta;                /* change in extent size */
  361. short            an_ed, j;            /* traditional loop counters */
  362. short            data_size;
  363. Handle            ext_data;            /* Handle to data block */
  364.  
  365. short            iac_code = noErr;    /* result from IAC call */
  366.  
  367.      the_data_H = (win_dataH) GetWRefCon(w_Ptr);
  368.     TextH =         (**the_data_H).wind_TEH;
  369.     the_extH =     (**the_data_H).the_extents;
  370.  
  371.     fmt_pref[0] = TXT_FMT;
  372.     fmt_pref[1] = 0;
  373.     HLock(the_extH);
  374.     ext_recs = *the_extH;
  375.     ext_data = NewHandle(0L);
  376.     /* need memory test here */
  377.  
  378.     an_ed = *the_ed + 1;
  379.     iac_code = iac_read_data(ext_recs[which].src_doc,
  380.                              (**the_data_H).the_slot,
  381.                              ext_recs[which].hat_check,
  382.                              &an_ed,
  383.                              &fmt_pref[0],
  384.                              &fmt_code,
  385.                              ext_data);
  386.  
  387.     if (iac_code == noErr)
  388.     {
  389.         ext_recs[which].ed_level = an_ed;    /* update extent */
  390.         *the_ed = an_ed;                    /* update caller */
  391.         data_size = GetHandleSize(ext_data);
  392.  
  393.         delta = data_size - (ext_recs[which].ext_end -
  394.                              ext_recs[which].ext_strt);
  395.  
  396.         TESetSelect (ext_recs[which].ext_strt,        /* select extent for TE */
  397.                      ext_recs[which].ext_end,
  398.                      TextH);
  399.         TEDelete(TextH);
  400.         HLock(ext_data);
  401.         TEInsert(*ext_data, data_size, TextH);    /* update text */
  402.         HUnlock(ext_data);
  403.         
  404.         ext_recs[which].ext_end = ext_recs[which].ext_strt + data_size;    /* update end (start unchanged) */
  405.  
  406.         if (delta)    /* only update if there was a change */
  407.         {
  408.             /* offset each following extent by change in size of this extent */
  409.             for (j=which+1; j<(**the_data_H).ext_cnt; j++)
  410.             {
  411.                 ext_recs[j].ext_strt += delta;
  412.                 ext_recs[j].ext_end +=  delta;
  413.             }
  414.         }
  415.     }
  416.  
  417.     HUnlock(the_extH);
  418.     DisposHandle (ext_data);        /* clean up */
  419.     return (iac_code);
  420. }
  421.  
  422.  
  423. /**
  424.  * Routine: ext_move
  425.  *
  426.  *        This routine checks to see if we have left the "current extent". If
  427.  *    we have, we check to see if we are the source for that extent. If so,
  428.  *    the contents of that extent are written to the IAC driver. If we are
  429.  *    instead mousing INTO an extent, that becomes the current extent.
  430.  */
  431.  
  432. # define __SEG__ Main
  433. void    ext_move(myEvent, w_Ptr)
  434.     EventRecord     *myEvent;
  435.     WindowPtr        w_Ptr;
  436. {
  437. EventRecord        anEvent;
  438. short            iac_code;            /* result from IAC call */
  439. OSErr            an_err;
  440. win_dataH        the_data_H;            /* data associated with a window */
  441. extentH            the_extH;            /* handle to extent block */
  442. exTable            ext_recs;            /* for updating old extent */
  443. TEHandle        TextH;                /* The TextEdit handle */
  444. short            i, the_ed, old_ext_no;
  445. short            data_size;
  446. extent            old_ext;            /* to check for change in extents */
  447. Handle            ext_data, t_base;
  448. long            *l_ptr;                /* recast to ease setting up hdr */
  449.  
  450. extern    Boolean ext_active;
  451.  
  452. extern    Boolean    chk_extent();
  453.  
  454. #define        HDR_SIZE 8
  455.  
  456.      the_data_H = (win_dataH) GetWRefCon(w_Ptr);
  457.     TextH =         (**the_data_H).wind_TEH;
  458.     the_extH =     (**the_data_H).the_extents;
  459.     ext_recs =     *the_extH;
  460.     old_ext_no = curr_ext_no;
  461.     anEvent =     *myEvent;        /* local copy for modification */
  462.  
  463.     GlobalToLocal(&anEvent.where);
  464.     TEClick(&anEvent.where, (anEvent.modifiers & shiftKey) != 0, TextH);
  465.  
  466.     if (ext_active)    /* we may need to write it's data to the IAC driver */
  467.     {
  468.         old_ext = curr_ext;
  469.         the_ed = curr_ext.ed_level;
  470.         ext_active = chk_extent(TextH, the_extH, (**the_data_H).ext_cnt);
  471.  
  472.         if ((old_ext.ext_strt != curr_ext.ext_strt) ||
  473.             !ext_active)    /* we left the current extent */
  474.         {
  475.             if (curr_ext.src_doc==(**the_data_H).doc_ID)    /* we were the source */
  476.             {
  477.                 iac_code = ext_write(TextH,
  478.                                      old_ext.ext_strt,
  479.                                      (old_ext.ext_end - old_ext.ext_strt),
  480.                                      (**the_data_H).doc_ID,
  481.                                      old_ext.hat_check,
  482.                                      &the_ed);
  483.                 ext_recs[old_ext_no].ed_level = the_ed;        /* update old extent just written */
  484.             }
  485.         }
  486.     }
  487.     else    /* see if we've moved into one! */
  488.     {
  489.         ext_active = chk_extent(TextH, the_extH, (**the_data_H).ext_cnt);
  490.         /* Since we weren't in an extent, there's nothing to write */
  491.     }
  492. }
  493.  
  494.  
  495. /**
  496.  * Routine: ext_remove
  497.  *
  498.  *        This routine severs a link in the drivers dependency table. It assumes
  499.  *    the driver will take care of removing any remaining data it sent.
  500.  */
  501.  
  502. # define __SEG__ Main
  503. void    ext_remove(w_Ptr, extP)
  504.     WindowPtr        w_Ptr;
  505.     extentP            extP;            /* extent to remove */
  506. {
  507. win_dataH        the_data_H;            /* data associated with a window */
  508. extentH            the_extH;            /* handle to extent block */
  509. short            iac_code;            /* result from IAC call */
  510.  
  511.      the_data_H = (win_dataH) GetWRefCon (w_Ptr);
  512.     iac_code = iac_remove_dependency((**the_data_H).doc_ID,
  513.                                      (**the_data_H).the_slot,
  514.                                      extP->hat_check);
  515. }
  516.  
  517.  
  518. /**
  519.  * Routine: poll_iac
  520.  *
  521.  *        This routine checks with the IAC driver to see if there's anything
  522.  *    to do. It checks at 1 second intervals to avoid excessive loading on
  523.  *    system capacity.
  524.  *
  525.  *    In order to simplify management of the extent ranges, extents are stored
  526.  *    in ascending order by starting position. This means that updating an
  527.  *    extent involves adjusting the start/end of all SUCCEEDING extents by the
  528.  *    amount the updated extent changes, but no preceeding extents need be
  529.  *    touched. Storing the extents in random order is definitely a poor idea.
  530.  */
  531.  
  532. # define __SEG__ Main
  533. void poll_iac(w_Ptr)
  534.     WindowPtr        w_Ptr;
  535. {
  536. win_dataH        the_data_H;            /* data associated with a window */
  537. extentH            the_extH;            /* handle to extent block */
  538. exTable            ext_recs;            /* for walking extents to read */
  539. TEHandle        TextH;                /* The TextEdit handle */
  540. short            slot_ID, vers, the_ed;    /* for IAC */
  541. long            fmt_code;            /* actual data format from IAC */
  542. long            fmt_pref[3];        /* format prefs, descending desirability */
  543. long            old_st, old_end;    /* TE selection before poll */
  544. long            my_docID;            /* so I don't read my own extents! */
  545. short            delta;                /* change in extent size */
  546. short            i,j;                /* traditional loop counters */
  547. Handle            ext_data;            /* Handle to data block */
  548.  
  549. short            iac_code = noErr;    /* result from IAC call */
  550. short            waiting = 0;        /* for IAC */
  551. short            doc_count = 0;        /* how many are open? */
  552.  
  553. extern    long    last_poll;                /* when we last polled IAC */
  554.  
  555.     if (TickCount() > (last_poll+POLL_INT))    /* minimum interval passed */
  556.     {
  557.         /* get relevent handles, etc */
  558.         the_data_H = (win_dataH) GetWRefCon (w_Ptr);
  559.         slot_ID =     (**the_data_H).the_slot;
  560.         the_extH =     (**the_data_H).the_extents;
  561.         TextH =         (**the_data_H).wind_TEH;
  562.         my_docID =     (**the_data_H).doc_ID;
  563.     
  564.         iac_code = iac_status(slot_ID, &vers, &doc_count, &waiting);
  565.     
  566.         if (waiting>0)    /* get data for each and update extents */
  567.         {
  568.             old_st =   (**TextH).selStart;    /* retain user's selection */
  569.             old_end =  (**TextH).selEnd;
  570.             ext_recs = *the_extH;            /* point to 1st extent */
  571.             for (i=0; i<(**the_data_H).ext_cnt; i++)
  572.             {
  573.                 if (my_docID != ext_recs[i].src_doc)    /* don't read my own! */
  574.                 {
  575.                     the_ed = ext_recs[i].ed_level + 1;    /* successor to last level read */
  576.                     iac_code = ext_read(w_Ptr, &the_ed, i);
  577.                     
  578.                     if (iac_code==noErr)
  579.                     {
  580.                         if ((waiting -= 1) == 0)
  581.                         {
  582.                             break;    /* stop if no extents left to do */
  583.                         }
  584.                     }
  585.                 }
  586.             } /* for */
  587.     
  588.             TESetSelect (old_st, old_end, TextH);    /* restore original */
  589.         }
  590.         
  591.         last_poll = TickCount();    /* update timer */
  592.     }
  593. }
  594.  
  595.  
  596. /**
  597.  * Routine: edit_init
  598.  *
  599.  *        This handles all the grunt initialization.
  600.  *        It returns NULL if everything went OK, non-NULL if unable to open
  601.  *        the IAC driver or we aren't operating under MultiFinder.
  602.  */
  603.  
  604. # define __SEG__ init
  605. short    edit_init()
  606. {
  607. short        i, k, menu_limit;
  608. Str255        itemString;
  609.  
  610. short        result = 0;        /* default optimism */
  611.  
  612. extern    MenuHandle    MyMenus[];
  613. extern    CursHandle    ibeamHdl;
  614. extern    long        last_poll;
  615.  
  616.     InitGraf(&qd.thePort);
  617.     InitFonts();
  618.     FlushEvents(everyEvent, 0);
  619.     InitWindows();
  620.     InitMenus();
  621.     TEInit();
  622.     InitDialogs(nil);
  623.     InitCursor();
  624.     ibeamHdl = GetCursor(iBeamCursor);
  625.     HNoPurge((Handle)ibeamHdl);        /* ensure we keep it */
  626.  
  627.     result = iac_open();    /* try to get IAC driver */
  628.     if (result != noErr)    /* couldn't get it! */
  629.     {
  630.         NumToString ((long) result, &itemString);
  631.         if (result==EARLY_SYS)
  632.         {
  633.             ParamText ("MultiFinder","",&itemString,"");
  634.         }
  635.         else
  636.         {
  637.             ParamText ("the IAC driver","",&itemString,"");
  638.         }
  639.     }
  640.     else                    /* got it! */
  641.     {
  642.         ext_active = false;            /* no "current extent" yet */
  643.         curr_ext.hat_check = 0;
  644.         curr_ext.ed_level =  0;
  645.         curr_ext.ext_strt =  0;
  646.         curr_ext.ext_end =   0;
  647.  
  648.         /* handle menu init'g (don't add link-display menu) */
  649.         menu_limit = menuCount-1;
  650.         for (i=appleMenu,k=appleID; i<menu_limit; i++,k++)
  651.         {
  652.             MyMenus[i] = GetMenu(k);
  653.         }
  654.         AddResMenu(MyMenus[appleMenu], (ResType) 'DRVR');
  655.         AddResMenu(MyMenus[fontMenu], (ResType) 'FONT');
  656.         for (i=0; i<menu_limit ;++i )
  657.         {
  658.             InsertMenu(MyMenus[i],0);
  659.         }
  660.  
  661.         /* set textstyling defaults */
  662.         GetFNum ("Geneva", &the_fNum);
  663.         the_size = 10;
  664.         CheckItem (MyMenus[sizeMenu], 2, true);
  665.         /* scan font menu to check default font */
  666.         for (i=1; i<=CountMItems (MyMenus[fontMenu]); i++)
  667.         {
  668.             GetItem (MyMenus[fontMenu], i, &itemString);
  669.             GetFNum (&itemString, &k);
  670.             if (k==geneva)
  671.                 {
  672.                     CheckItem (MyMenus[fontMenu], i, true);
  673.                     break;
  674.                 }
  675.         }
  676.         DrawMenuBar();                /* now user can see menu bar */
  677.         last_poll = TickCount();    /* so we can poll @ 1-sec intervals */
  678.     }
  679.  
  680.     return(result);
  681. }
  682.  
  683.  
  684. /**
  685.  * Routine: menu_tree
  686.  *
  687.  *        This is the standard menu-processing tree.
  688.  */
  689.  
  690. # define __SEG__ Main
  691. void    menu_tree(menu_sel)
  692.     long    menu_sel;    /* menu/item selected */
  693. {
  694. short            the_menu, the_item;
  695. GrafPtr         savePort;
  696. char            daName[256];
  697. Str255            itemString;            /* font selection */
  698. short            i;
  699. win_dataH        the_data_H;            /* data associated with a window */
  700. extentP            extP;                /* pointer to an extent to zap on quitting */
  701. TEHandle        TextH;                /* The TextEdit handle */
  702.  
  703. extern short        the_fNum, the_size;        /* current attributes */
  704. extern Style        the_style;
  705. extern MenuHandle    MyMenus[];
  706. extern Boolean        DoneFlag;
  707.  
  708. extern void        about_box();
  709. extern short    open_doc(), create_doc(), close_doc(), save_doc();
  710. extern void        do_clear(), do_copy(), do_cut(), do_paste();
  711. extern void        do_hotCopy(), do_hotPaste(), killLink_box(), ext_remove();
  712. extern void        link_display(), linkInfo_box();
  713.  
  714.  
  715.     the_item = LOWORD(menu_sel);
  716.     the_menu = HIWORD(menu_sel);            /* This is the resource ID */
  717.  
  718.     if (myWindow)
  719.     {
  720.         the_data_H = (win_dataH) GetWRefCon (myWindow);
  721.         TextH = (**the_data_H).wind_TEH;
  722.     }
  723.  
  724.     switch (the_menu)
  725.     {
  726.         case appleID:
  727.             if (the_item == aboutMeCommand) 
  728.             {
  729.                 about_box();
  730.             }
  731.             else
  732.             {
  733.                 GetItem(MyMenus[appleMenu], the_item, daName);
  734.                 GetPort(&savePort);
  735.                 (void) OpenDeskAcc(daName);
  736.                 SetPort(savePort);
  737.             }
  738.             break;
  739.  
  740.         case fileID:
  741.             switch (the_item)
  742.             {
  743.                 case newCommand:
  744.                     (void) create_doc();
  745.                     break;
  746.  
  747.                 case openCommand:
  748.                     (void) open_doc();
  749.                     break;
  750.  
  751.                 case closeCommand:
  752.                     (void) close_doc();
  753.                     break;
  754.  
  755.                 case saveCommand:
  756.                     (void) save_doc();
  757.                     break;
  758.  
  759.                 case quitCommand:
  760.                     DoneFlag = true;            /* I want out! */                    
  761.                     for (i=0; i<(**the_data_H).ext_cnt; i++)
  762.                     {
  763.                         extP = (*(**the_data_H).the_extents) +
  764.                                (i * sizeof(extent));
  765.                         ext_remove(myWindow, extP);
  766.                     }
  767.                     break;
  768.  
  769.                 default:
  770.                     break;
  771.             }
  772.             break;    /* fileID */
  773.  
  774.         case editID:
  775.             switch (the_item)
  776.             {
  777.                 case undoCommand:    /* not implemented yet (if ever!) */
  778.                     break;
  779.  
  780.                 case cutCommand:
  781.                     do_cut();
  782.                     break;
  783.  
  784.                 case copyCommand:
  785.                     do_copy();
  786.                     break;
  787.  
  788.                 case pasteCommand:
  789.                     do_paste();
  790.                     break;
  791.  
  792.                 case clearCommand:
  793.                     do_clear();
  794.                     break;
  795.  
  796.                 case hotCopyCommand:
  797.                     do_hotCopy();
  798.                     break;
  799.  
  800.                 case hotPasteCommand:
  801.                     do_hotPaste();
  802.                     break;
  803.  
  804.                 case zapLinkCommand:
  805.                     killLink_box();
  806.                     break;
  807.                 
  808.                 default:
  809.                     break;
  810.             }
  811.             break;    /* editID */
  812.  
  813.         case optionsID:
  814.             switch (the_item)
  815.             {
  816.                 case showLinksCmd:
  817.                     break;
  818.  
  819.                 case showLinkInfoCmd:
  820.                     linkInfo_box();
  821.                     break;
  822.  
  823.                 default:
  824.                     break;
  825.             }
  826.             break;    /* optionsID */
  827.  
  828.         case fontID:
  829.             for (i=1; i<=CountMItems(MyMenus[fontMenu]); i++)
  830.             {
  831.                 CheckItem (MyMenus[fontMenu], i, false);    /* uncheck old font */
  832.             }
  833.             CheckItem (MyMenus[fontMenu], the_item, true);
  834.             GetItem (MyMenus[fontMenu], the_item, &itemString);
  835.             GetFNum (&itemString, &the_fNum);
  836.             for (i=0; i<8; i++)        /* set real sizes */
  837.             {
  838.                 if (RealFont (the_fNum,f_sizes[i]))
  839.                 {
  840.                     SetItemStyle (MyMenus[sizeMenu], i+1, outline);
  841.                 }
  842.                 else
  843.                 {
  844.                     SetItemStyle (MyMenus[sizeMenu], i+1, normal);
  845.                 }
  846.             }
  847.             if (myWindow)    /* force a refresh */
  848.             {
  849.                 SetPort (myWindow);
  850.                 TextFont (the_fNum);
  851.                 (**TextH).txFont = the_fNum;
  852.                 TECalText (TextH);                
  853.                 InvalRect (&myWindow->portRect);
  854.             }
  855.             break;
  856.  
  857.         case sizeID:
  858.             if (the_item<9)        /* setting new size */
  859.             {
  860.                 for (i=1; i<9; i++)        /* remove all checkmarks first */
  861.                 {
  862.                     CheckItem (MyMenus[sizeMenu], i, false);
  863.                 }
  864.                 the_size = f_sizes[the_item-1];
  865.                 CheckItem (MyMenus[sizeMenu], the_item, true);
  866.             }
  867.             else                /* setting style */
  868.             {
  869.                 if (the_style & f_styles[the_item-10])    /* already on? */
  870.                 {
  871.                     the_style &= (~f_styles[the_item-10]);    /* turn off */
  872.                     CheckItem (MyMenus[sizeMenu], the_item, false);
  873.                 }
  874.                 else
  875.                 {
  876.                     the_style |= f_styles[the_item-10];
  877.                     CheckItem (MyMenus[sizeMenu], the_item, true);
  878.                 }
  879.             }
  880.             if (myWindow)    /* force a refresh */
  881.             {
  882.                 SetPort (myWindow);
  883.                 TextFace (the_style);
  884.                 TextSize (the_size);
  885.                 (**TextH).txFace = the_style;
  886.                 (**TextH).txSize = the_size;
  887.                 TECalText (TextH);
  888.                 InvalRect (&myWindow->portRect);
  889.             }
  890.             break;
  891.  
  892.         case linkDisplayID:
  893.             link_display(the_item - 1);        /* zero-based extent subscripts */
  894.             break;
  895.  
  896.         default:
  897.             break;
  898.     }    /* end switch(the_menu) */
  899.  
  900.     HiliteMenu(0);
  901.  
  902.     return;
  903. }
  904.  
  905.  
  906. /**
  907.  * Routine: add_display_cmd()
  908.  *
  909.  *        This is the routine that is called whenever a link is completed.
  910.  *    It adds a menu item to the "Links" menu so the user can highlight
  911.  *    any visible links in a distinctive fashion.
  912.  */
  913.  
  914. # define __SEG__ Main
  915. void    add_display_cmd(which, total)
  916.     short    which;        /* position in extent array */
  917.     short    total;        /* total # of extents */
  918. {
  919. win_dataH        the_data_H;            /* data associated with a window */
  920. extentH            the_extH;            /* handle to extent block */
  921. exTable            ext_recs;
  922. Str255            num_str, cmd_str;    /* for building menu item */
  923.  
  924.  
  925.      the_data_H = (win_dataH) GetWRefCon (myWindow);
  926.     the_extH =     (**the_data_H).the_extents;
  927.     ext_recs =     *the_extH;
  928.  
  929.     if ((**the_data_H).ext_cnt)    
  930.     {
  931.         if (!link_menu)        /* need to create link menu */
  932.         {
  933.             MyMenus[linkdDispMenu] = GetMenu(linkDisplayID);
  934.             InsertMenu(MyMenus[linkdDispMenu],0);
  935.             link_menu = true;
  936.         }
  937.  
  938.         NumToString ((long) total, &num_str);
  939.         if (ext_recs[which].src_doc == (**the_data_H).doc_ID)
  940.         {
  941.             strcpy(&cmd_str, "Source extent ");
  942.         }
  943.         else
  944.         {
  945.             strcpy(&cmd_str, "Target extent ");
  946.         }
  947.         (void) strcat(&cmd_str, &num_str);    /* build complete menu item */
  948.         AppendMenu (MyMenus[linkdDispMenu], &cmd_str);
  949.  
  950.         DrawMenuBar();                /* now user can see menu bar again */
  951.     }
  952. }
  953.  
  954. # define __SEG__ Main
  955. void    link_display(ext_no)
  956.     short        ext_no;        /* which extent to highlight */
  957. {
  958. win_dataH        the_data_H;            /* data associated with a window */
  959. extentH            the_extH;            /* handle to extent block */
  960. exTable            ext_recs;            /* ptr to array of extents */
  961. short            old_st, old_end;    /* previous selection range */
  962. TEHandle        TextH;                /* The TextEdit handle */
  963.  
  964. extern void    SourceHigh();            /* assembler highlighting routine */
  965.  
  966.      the_data_H = (win_dataH) GetWRefCon (myWindow);
  967.     the_extH =     (**the_data_H).the_extents;
  968.     TextH =         (**the_data_H).wind_TEH;
  969.     ext_recs =      *the_extH;
  970.  
  971.     old_st =  (**TextH).selStart;
  972.     old_end = (**TextH).selEnd;
  973.  
  974.     /* put a routine address into teHiHook for new highlighting routine */
  975.     (**TextH).highHook = &SourceHigh();
  976.     TESetSelect ((long) ext_recs[ext_no].ext_strt,
  977.                  (long) ext_recs[ext_no].ext_end,
  978.                          TextH);
  979.  
  980.     while (!Button()) ;        /* wait for mouse-down */
  981.     while (Button()) ;        /* and following mouse-up */
  982.  
  983.     /* clear teHiHook to restore normal highlighting */
  984.     TESetSelect ((long) old_st, (long) old_end, TextH);        /* unhighligh extent */
  985.     (**TextH).highHook = nil;
  986. }
  987.